/**
 *******************************************************************************
 * @FileName  : att_api.h
 * @Author    : GaoQiu
 * @CreateDate: 2020-02-18
 * @Copyright : Copyright(C) GaoQiu
 *              All Rights Reserved.
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * GaoQiu and is available under the terms of Commercial License Agreement
 * between GaoQiu and the licensee in separate contract or the terms described
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */
#ifndef ATT_API_H_
#define ATT_API_H_

#include "utils/mdc.h"
#include "att_defs.h"
#include "stack/ble_types.h"


/*! 4B(l2cap head) + mtu(user ATT_MTU) */
#define ATT_MTU_BUF_SIZE(mtu)  (4 + (mtu))

/**
 *  @Name: ATT Server Attribute Settings
 *         Settings that may be set on each attribute.
 *  @{
 */
#define ATTS_SET_NONE                    0x00
#define ATTS_SET_UUID_128                0x01    /*!< Set if the UUID is 128 bits in length */
#define ATTS_SET_WRITE_CBACK             0x02    /*!< Set if the group callback is executed when
                                                             this attribute is written by a client device */
#define ATTS_SET_READ_CBACK              0x04    /*!< Set if the group callback is executed when
                                                             this attribute is read by a client device */
#define ATTS_SET_VARIABLE_LEN            0x08    /*!< Set if the attribute has a variable length */
#define ATTS_SET_ALLOW_OFFSET            0x10    /*!< Set if writes are allowed with an offset */
#define ATTS_SET_CCC                     0x20    /*!< Set if the attribute is a client characteristic
                                                             configuration descriptor */
#define ATTS_SET_ALLOW_SIGNED            0x40    /*!< Set if signed writes are allowed */
#define ATTS_SET_REQ_SIGNED              0x80    /*!< Set if signed writes are required if link is not encrypted */
/**@}*/


/**
 * @Name: ATT Server Attribute Permissions
 *        Permissions used to describe a attribute's security setting.
 *        These values can be set in any combination.
 * @{
 */
#define ATTS_PERMIT_READ                 0x01    /*!< Set if attribute can be read */
#define ATTS_PERMIT_READ_AUTH            0x02    /*!< Set if attribute read requires authentication */
#define ATTS_PERMIT_READ_AUTHORIZ        0x04    /*!< Set if attribute read requires authorization */
#define ATTS_PERMIT_READ_ENC             0x08    /*!< Set if attribute read requires encryption */
#define ATTS_PERMIT_WRITE                0x10    /*!< Set if attribute can be written */
#define ATTS_PERMIT_WRITE_AUTH           0x20    /*!< Set if attribute write requires authentication */
#define ATTS_PERMIT_WRITE_AUTHORIZ       0x40    /*!< Set if attribute write requires authorization */
#define ATTS_PERMIT_WRITE_ENC            0x80    /*!< Set if attribute write requires encryption */
/**@}*/

#pragma pack(1) /* 1byte alignment. */

/** @brief Encode 128 bit UUID into array values in little-endian format.
 *
 *  Helper macro to initialize a 128-bit UUID array value from the readable form
 *  of UUIDs, or encode 128-bit UUID values into advertising data
 *  Can be combined with BT_UUID_DECLARE_128 to declare a 128-bit UUID.
 *
 *  Example of how to declare the UUID `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
 *
 *  @code
 *  BT_UUID_DECLARE_128(
 *       BT_UUID_128_ENCODE(0x6E400001, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E))
 *  @endcode
 *
 *  Example of how to encode the UUID `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
 *  into advertising data.
 *
 *  @code
 *  BT_DATA_BYTES(BT_DATA_UUID128_ALL,
 *       BT_UUID_128_ENCODE(0x6E400001, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E))
 *  @endcode
 *
 *  Just replace the hyphen by the comma and add `0x` prefixes.
 *
 *  @param w32 First part of the UUID (32 bits)
 *  @param w1  Second part of the UUID (16 bits)
 *  @param w2  Third part of the UUID (16 bits)
 *  @param w3  Fourth part of the UUID (16 bits)
 *  @param w48 Fifth part of the UUID (48 bits)
 *
 *  @return The comma separated values for UUID 128 initializer that
 *          may be used directly as an argument for
 *          @ref BT_UUID_INIT_128 or @ref BT_UUID_DECLARE_128
 */
#define UUID_128_ENCODE(w32, w1, w2, w3, w48) \
	(((w48) >>  0) & 0xFF), \
	(((w48) >>  8) & 0xFF), \
	(((w48) >> 16) & 0xFF), \
	(((w48) >> 24) & 0xFF), \
	(((w48) >> 32) & 0xFF), \
	(((w48) >> 40) & 0xFF), \
	(((w3)  >>  0) & 0xFF), \
	(((w3)  >>  8) & 0xFF), \
	(((w2)  >>  0) & 0xFF), \
	(((w2)  >>  8) & 0xFF), \
	(((w1)  >>  0) & 0xFF), \
	(((w1)  >>  8) & 0xFF), \
	(((w32) >>  0) & 0xFF), \
	(((w32) >>  8) & 0xFF), \
	(((w32) >> 16) & 0xFF), \
	(((w32) >> 24) & 0xFF)

typedef union{
	uint16_t UUID_16;
	uint8_t  UUID_128[16];
}UUID_t;

typedef struct{
	uint8_t   prop;
	uint16_t  attHandle;
	UUID_t    UUID;
}char_prop_t;
#pragma pack() /* Restore 4byte alignment. */

/*! ATT error code. */
enum{
	ATT_SUCCESS                     = 0x00, /*!< success */
	ATT_ERR_INVALID_HANDLE          = 0x01, /*!< Attribute handle value given was not valid on this attribute server */
	ATT_ERR_READ_NOT_PERMITTED      = 0x02, /*!< Attribute cannot be read */
	ATT_ERR_WRITE_NOT_PERMITTED     = 0x03, /*!< Attribute cannot be written */
	ATT_ERR_INVALID_PDU             = 0x04, /*!< The attribute PDU was invalid */
	ATT_ERR_INSUFFICIENT_AUTHEN     = 0x05, /*!< The attribute requires authentication before it can be read or written */
	ATT_ERR_UNSUPPORTED_REQ         = 0x06, /*!< Attribute server doesn't support the request received from the attribute client */
	ATT_ERR_INVALID_OFFSET          = 0x07, /*!< Offset specified was past the end of the attribute */
	ATT_ERR_INSUFFICIENT_AUTHOR     = 0x08, /*!< The attribute requires an authorization before it can be read or written */
	ATT_ERR_PREPARE_QUEUE_FULL      = 0x09, /*!< Too many prepare writes have been queued */
	ATT_ERR_ATTR_NOT_FOUND          = 0x0a, /*!< No attribute found within the given attribute handle range */
	ATT_ERR_ATTR_NOT_LONG           = 0x0b, /*!< Attribute cannot be read or written using the Read Blob Request or Prepare Write Request */
	ATT_ERR_INSUFFICIENT_KEY_SIZE   = 0x0c, /*!< The Encryption Key Size used for encrypting this link is insufficient */
	ATT_ERR_INVALID_VALUE_SIZE      = 0x0d, /*!< The attribute value length is invalid for the operation */
	ATT_ERR_UNLIKELY                = 0x0e, /*!< The attribute request that was requested has encountered an error that was very unlikely, and therefore could not be completed as requested */
	ATT_ERR_INSUFFICIENT_ENCRYPT    = 0x0f, /*!< The attribute requires encryption before it can be read or written */
	ATT_ERR_UNSUPPORTED_GRP_TYPE    = 0x10, /*!< The attribute type is not a supported grouping attribute as defined by a higher layer specification */
	ATT_ERR_INSUFFICIENT_RESOURCES  = 0x11, /*!< Insufficient Resources to complete the request */
	ATT_ERR_DATABASE_OUT_OF_SYNC    = 0x12, /*!< Client out of synch with database */
	ATT_ERR_VALUE_NOT_ALLOWED       = 0x13, /*!< Value not allowed */

	/* Application error code */
	ATT_ERR_VALUE_RANGE            = 0x80,
	ATT_ERR_UNKNOWN_CCC_OPT        = 0x81,
};

#define ATT_CBACK_START   0x00
/*! ATT client callback events */
enum                                          /*!< Internal note: event values match method values */
{
	ATTC_ERR_RSP      = ATT_CBACK_START,      /*!< Error response */
	ATTC_FIND_INFO_RSP,                       /*!< Find information response */
	ATTC_FIND_BY_TYPE_VALUE_RSP,              /*!< Find by type value response */
	ATTC_READ_BY_TYPE_RSP,                    /*!< Read by type value response */
	ATTC_READ_RSP,                            /*!< Read response */
	ATTC_READ_LONG_RSP,                       /*!< Read long response */
	ATTC_READ_MULTIPLE_RSP,                   /*!< Read multiple response */
	ATTC_READ_BY_GROUP_TYPE_RSP,              /*!< Read group type response */
	ATTC_WRITE_RSP,                           /*!< Write response */
	ATTC_WRITE_CMD_RSP,                       /*!< Write command response */
	ATTC_PREPARE_WRITE_RSP,                   /*!< Prepare write response */
	ATTC_EXECUTE_WRITE_RSP,                   /*!< Execute write response */
	ATTC_HANDLE_VALUE_NTF,                    /*!< Handle value notification */
	ATTC_HANDLE_VALUE_IND,                    /*!< Handle value indication */

	/* ATT server callback events */
	ATTS_HANDLE_VALUE_CNF,                    /*!< Handle value confirmation */
	ATTS_CCC_STATE_IND,                       /*!< Client chracteristic configuration state change */
	ATTS_DB_HASH_CALC_CMPL_IND,               /*!< Database hash calculation complete */

	/* ATT common callback events */
	ATT_MTU_UPDATE_IND                        /*!< Negotiated MTU value */
};

/*! ATT call-back event. */
typedef struct{
	MdcMsgHdr_t   hdr;
	uint8_t      *pValue;
	uint16_t      valueLen;
	uint16_t      handle;
	uint16_t      mtu;
}AttEvt_t;

typedef void (*AttEvtCback_t)(AttEvt_t *pEvt);

/* Attribute structure */
typedef struct{
	uint8_t  const *pUuid;           /*!< Pointer to the attribute's UUID */
	uint8_t        *pValue;          /*!< Pointer to the attribute's value */
	uint16_t       *pLen;            /*!< Pointer to the length of the attribute's value */
	uint16_t        maxLen;          /*!< Maximum length of attribute's value */
	uint8_t         settings;        /*!< Attribute settings */
	uint8_t         permissions;     /*!< Attribute permissions */
}AttsAttr_t;

#define GATT_CHARACTER_DEFINE(pUuid, pValue, pLen, maxLen, settings, attPerim)  \
{ \
  (uint8_t*)pUuid, \
  (uint8_t*)pValue,\
  (uint16_t *)pLen, \
  maxLen,\
  settings,\
  attPerim,\
},

/* Attribute Read call-back */
typedef AttState_t (*attrReadCback_t)(uint16_t connHandle, uint16_t attHandle, uint8_t opcode,
		                              uint16_t offset, AttsAttr_t* pAttr);
/* Attribute write call-back */
typedef AttState_t (*attrWriteCback_t)(uint16_t connHandle, uint16_t attHandle, uint8_t opcode, uint16_t offset,
		                               uint8_t *pValue, uint32_t len, AttsAttr_t* pAttr);

/* Attribute Group structure */
typedef struct AttsGroup_s{
	struct AttsGroup_s   *pNext;

	AttsAttr_t           *pAttr;
	attrReadCback_t       readCback;
	attrWriteCback_t      writeCback;
	uint16_t              startHandle;
	uint16_t              endHandle;
}AttsGroup_t;

#define GATT_SVC_GRP_DECLARE(grpName, pGrp, WriteCback, ReadCback, startHandle, endHandle)\
AttsGroup_t  grpName = {\
	NULL, \
	(AttsAttr_t *)&pGrp[0],\
	ReadCback,\
	WriteCback,\
	startHandle,\
	endHandle,\
};

/**
 *  @brief:  ATTS authorization call-back type
 *
 *  This call-back function is executed when a read or write operation occurs
 *  and the security field of an attribute structure is set to
 *  ATTS_PERMIT_READ_AUTHORIZ or  ATTS_PERMIT_WRITE_AUTHORIZ respectively.
 *
 *  @param: connHandle  connHandle
 *  @param: permit       Set to  ATTS_PERMIT_WRITE for a write operation or ATTS_PERMIT_READ for a read operation.
 *  @param: handle       Attribute handle.
 *
 *  @return: status of the operation.  ATT_SUCCESS if successful, else if failure
 *            the ATT_ERR_AUTH is typically returned.
 */
typedef uint8_t (*attsAuthorCback_t)(uint16_t connHandle, uint8_t permit, uint16_t attHandle);

typedef uint8_t (*AttsCccCback_t)(uint16_t connHandle, uint16_t attHandle, uint8_t *pValue);

typedef struct{
	uint16_t attHandle;
	uint8_t  secLevel;
}AttsCccSets_t;

void ATT_Init(void);
void ATT_EvtRegister(AttEvtCback_t evtCback);
uint16_t ATT_GetMtu(uint16_t connHandle);

//ATT Server API
void ATTS_Init(void);
void ATTS_AddAttGroup(AttsGroup_t *attGrp);

BleState_t ATTS_ValueNotify(uint16_t connHandle, uint16_t attHandle, uint8_t *pvalue, uint32_t len);
BleState_t ATTS_ValueIndicate(uint16_t connHandle, uint16_t attHandle, uint8_t *pvalue, uint32_t len);

//ATT CCC API
void ATTS_CccRegister(AttsCccSets_t *pSets, uint8_t len, AttsCccCback_t cback);
uint16_t ATTS_GetCccValue(uint16_t connHandle, uint8_t idx);
void ATTS_SetCccValue(uint16_t connHandle, uint8_t idx, uint16_t value);
uint16_t ATTS_CccEnabled(uint16_t connHandle, uint8_t idx);

//ATT Client API
void ATTC_Init(void);

BleState_t ATTC_SendMtuReq(uint16_t connHandle, uint16_t mtu);

BleState_t ATTC_SendFindInfoReq(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle);
BleState_t ATTC_SendFIndByTypeValueReq(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle,
		                               uint16_t uuid, uint8_t *pValue, uint32_t len);

BleState_t ATTC_SendReadByTypeReq(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle,
		                          uint8_t *pUuid, uint32_t len);
BleState_t ATTC_SendReadReq(uint16_t connHandle, uint16_t attHandle);
BleState_t ATTC_SendReadBlobReq(uint16_t connHandle, uint16_t attHandle, uint16_t offset);
BleState_t ATTC_SendReadMultiReq(uint16_t connHandle, uint16_t *pAttHandleSet, uint32_t attHandleNum);
BleState_t ATTC_SendReadByGroupTypeReq(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle,
                                       uint8_t *pUuid, uint32_t len);

BleState_t ATTC_SendWriteReq(uint16_t connHandle, uint16_t attHandle, uint8_t *pValue, uint32_t len);
BleState_t ATTC_SendWriteCmd(uint16_t connHandle, uint16_t attHandle, uint8_t *pValue, uint32_t len);
BleState_t ATTC_SendSignedWriteCmd(uint16_t connHandle, uint16_t attHandle,
		                           uint8_t *pValue, uint32_t len, uint8_t *pAuthenSign);

BleState_t ATTC_SendPrepareWriteReq(uint16_t connHandle, uint16_t attHandle, uint8_t *pValue, uint32_t len);
BleState_t ATTC_SendExecWriteReq(uint16_t connHandle, uint8_t flag);

BleState_t ATTC_SendValueConfirm(uint16_t connHandle);

//ATTC Discovery
typedef struct{
	union{
		uint8_t  uuid_128[16];
		uint16_t uuid_16;
	};
	uint8_t len;
}uuid_t;

typedef struct{
	uint16_t   startHandle;
	uint16_t   endHandle;
	uuid_t     uuid;
}attSvc_t;

typedef struct{
	uint16_t    defHandle;   /*! The handle of the GATT characteristic definition. */
	uint16_t    valHandle;   /*! The handle of the GATT characteristic value. */
	uuid_t      uuid;        /*! The properties of the GATT characteristic. */
	uint8_t     prop;
}attChr_t;

typedef struct{
	uint16_t    handle;
	uint16_t    value; /*!< use for CCCD */
	uuid_t      uuid;
}attDsc_t;

typedef struct{
	uint16_t     status;
	uint16_t     attHandle;
}attDiscState_t;

typedef int (attDiscSvcCback_t)(uint16_t connHandle, attDiscState_t state, attSvc_t *pSvr, void *arg);
typedef int (attDiscChrCback_t)(uint16_t connHandle, attDiscState_t state, attChr_t *pSvr, void *arg);
typedef int (attDiscDscCback_t)(uint16_t connHandle, attDiscState_t state, attDsc_t *pSvr, void *arg);
typedef int (attSetCccdCback_t)(uint16_t connHandle, attDiscState_t state, void *arg);

/**
 * Services Discovery
 */
int ATTC_DiscAllSvcs(uint16_t connHandle, attDiscSvcCback_t *attSvrDiscCback, void *arg);

int ATTC_DiscAllChrs(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle, attDiscChrCback_t *attChrDiscCback, void *arg);

int ATTC_DiscAllDscs(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle, attDiscDscCback_t *attDscDiscCback, void *arg);
int ATTC_DiscAllCCCD(uint16_t connHandle, uint16_t startHandle, uint16_t endHandle, attDiscDscCback_t *attDscDiscCback, void *arg);

int ATTC_SetCCCD(uint16_t connHandle, uint16_t attHandle, uint16_t value, attSetCccdCback_t *attSetCccdCback, void *arg);

#endif /* ATT_API_H_ */
